<?php


namespace App\Services\Company\Services;

use App\Businesses\BusinessState;
use App\Events\OrderCancelEvent;
use App\Events\CompanyPaymentSuccessEvent;
use App\Exceptions\ServiceException;
use App\Services\Base\Interfaces\ConfigServiceInterface;
use App\Services\Business\Models\Expiredables;
use App\Services\Order\Models\Coupon;
use App\Services\Order\Models\OrderPaidRecord;
use App\Services\Order\Models\OrderRefund;
use App\Services\Company\Models\CompanyOrder;
use App\Services\Company\Models\CompanyOrderGoods;
use App\Services\Company\Models\CompanyOrderPaidRecord;
use App\Services\Order\Models\UserCoupon;
use App\Services\Company\Interfaces\CompanyOrderServiceInterface;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;


class CompanyOrderService implements CompanyOrderServiceInterface
{
    protected $configService;
    protected $businessState;

    public function __construct(ConfigServiceInterface $configService, BusinessState $businessState)
    {
        $this->configService = $configService;
        $this->businessState = $businessState;
    }

    /**
     * @param int $userId
     * @param int $total
     * @param array $goodsItems
     * @param int $promoId
     * @return mixed
     */
    public function createOrder(int $companyId, int $userId, int $total, array $goodsItems, int $couponId)
    {
        return DB::transaction(function () use ($companyId,$userId, $total, $goodsItems,  $couponId) {
            // 优惠码抵扣

            $couponDiscount = 0;

            // 优惠券抵扣
            $coupon = Coupon::query()->where('id', $couponId)->first();
            $userCoupon = UserCoupon::query()->where('coupon_id', $couponId)->where('user_id', $userId)->first();
            if ($coupon && $this->businessState->couponCanUse($userId, $coupon->toArray(), $userCoupon->toArray())) {
                $couponDiscount = $coupon['reduce_count'];
                // 记录使用次数
                $coupon->increment('used_times', 1);
            }

            // 订单状态
            $orderStatus = CompanyOrder::STATUS_UNPAY;
            if ($total  - $couponDiscount <= 0) {
                $orderStatus = CompanyOrder::STATUS_PAID;
            }

            $order = CompanyOrder::create([
                'company_id'=>$companyId,
                'user_id' => $userId,
                'charge' => $total,
                'status' => $orderStatus,
                'order_id' => $this->genOrderNo($companyId),
            ]);

            $orderGoodsItems = [];
            foreach ($goodsItems as $goodsItem) {
                $orderGoodsItems[] = [
                    'user_id' => $userId,
                    'company_id'=>$companyId,
                    'oid' => $order['id'],
                    'num' => 1,
                    'charge' => $goodsItem['charge'],
                    'goods_id' => $goodsItem['id'],
                    'goods_type' => $goodsItem['type'],
                    'goods_expired_id' => $goodsItem['goods_expired_id']??0,
                    'goods_name' => $goodsItem['goods_name'] ?? '',
                    'goods_charge' => (int)($goodsItem['goods_charge'] ?? ''),
                    'goods_ori_charge' => (int)($goodsItem['goods_ori_charge'] ?? ''),

                ];
            }
            CompanyOrderGoods::insert($orderGoodsItems);



            if ($couponDiscount > 0) {
                CompanyOrderPaidRecord::create([
                    'user_id' => $userId,
                    'company_id'=>$companyId,
                    'order_id' => $order['id'],
                    'paid_total' => $couponDiscount,
                    'paid_type' => CompanyOrderPaidRecord::PAID_TYPE_COUPON_CODE,
                    'paid_type_id' => $coupon['id']
                ]);
            }

            // 订单支付事件
            if ($order['status'] === CompanyOrder::STATUS_PAID) {
                event(new CompanyPaymentSuccessEvent($order->toArray()));
            }

            return $order->toArray();
        });
    }






    /**
     * @param int $userId
     * @param array $role
     * @param int $promoId
     * @return array
     */
    public function createRoleOrder(int $companyId, int $userId, int $expiredId, array $role, int $couponId): array
    {
        $expiredRecord = Expiredables::query()->where('id',$expiredId)->first();
        return $this->createOrder($companyId,$userId, $expiredRecord['charge'], [
            [
                'id' => $role['id'],
                'company_id'=>$companyId,
                'charge' => $expiredRecord['charge']??0,
                'type' => CompanyOrderGoods::GOODS_TYPE_ROLE,
                'goods_name' => $role['title'] ?? '',
                'goods_expired_id' =>$expiredId,
                'goods_charge' => $expiredRecord['charge'] ?? 0,
                'goods_ori_charge' => $expiredRecord['charge'] ?? 0,
            ]
        ],$couponId);
    }

    /**
     * @param int $shopId
     * @return string
     * @throws \Exception
     */
    protected function genOrderNo(int $shopId): string
    {
        $prefix = "s";
        $time = date('His');
        $rand = random_int(10, 99);

        return $prefix.$shopId . $time . $rand;
    }

    public function findOrFail(string $orderId): array
    {
        return CompanyOrder::query()->where('order_id', $orderId)->firstOrFail()->toArray();
    }

    public function findCompany(int $companyId, string $orderId): array
    {
        return CompanyOrder::query()
            ->where('company_id', $companyId)
            ->where('order_id', $orderId)
            ->firstOrFail()
            ->toArray();
    }

    public function findId(int $id): array
    {
        return CompanyOrder::query()->where('id', $id)->firstOrFail()->toArray();
    }

    /**
     * @param int $id
     * @param array $data
     *
     * @throws ServiceException
     */
    public function change2Paying(int $id, array $data): void
    {
        $order = CompanyOrder::findOrFail($id);
        $data['status'] = CompanyOrder::STATUS_PAYING;
        $order->update($data);
    }

    /**
     * @param int $id
     *
     * @throws ServiceException
     */
    public function cancel(int $id): void
    {
        $order = CompanyOrder::findOrFail($id);
        if (!in_array($order->status, [CompanyOrder::STATUS_PAYING, CompanyOrder::STATUS_UNPAY])) {
            throw new ServiceException('order status error');
        }
        $order->update(['status' => CompanyOrder::STATUS_CANCELED]);

        event(new OrderCancelEvent($order['id']));
    }

    public function getCompanyOrders(int $shopId, int $status, string $keywords, int $page, int $size): array
    {
        $query = CompanyOrder::query()->where('company_id', $shopId);
        $total = $query->count();
        $list = $query
            ->with(['goods:id,oid,goods_id,goods_type,goods_name,goods_charge,goods_ori_charge,num,charge,goods_expired_id'])
            ->when($status, function ($query) use ($status) {
                $query->where('status', $status);
            })
            ->when($keywords, function ($query) use ($keywords) {
                $query->orWhere('title', 'like', '%' . $keywords . '%');
            })
            ->latest()
            ->forPage($page, $size)
            ->get()
            ->toArray();

        return compact('total', 'list');
    }

    /**
     * 订单改为已完成
     *
     * @param int $id
     */
    public function changePaid(int $id): void
    {
        CompanyOrder::query()->where('id', $id)->firstOrFail()->update(['status' => CompanyOrder::STATUS_PAID]);
    }

    /**
     * 获取订单的商品
     *
     * @param int $id
     * @return array
     */
    public function getOrderProducts(int $id): array
    {
        $product =  CompanyOrderGoods::query()->where('oid', $id)->get()->first();
        return $product? $product->toArray():[];
    }

    /**
     * 获取超时订单
     *
     * @param string $date
     * @return array
     */
    public function getTimeoutOrders(string $date): array
    {
        return CompanyOrder::query()
            ->whereIn('status', [CompanyOrder::STATUS_UNPAY, CompanyOrder::STATUS_PAYING])
            ->where('created_at', '<=', $date)
            ->get()
            ->toArray();
    }

    /**
     * @param int $id
     * @return int
     */
    public function getOrderPaidRecordsTotal(int $id): int
    {
        return intval(CompanyOrderPaidRecord::whereOrderId($id)->sum('paid_total'));
    }


    /**
     * @param int $id
     * @param int $userId
     * @param int $paidTotal
     */
    public function createOrderPaidRecordDefault(int $id, int $shopId, int $userId, int $paidTotal): void
    {
        CompanyOrderPaidRecord::create([
            'company_id'=>$shopId,
            'user_id' => $userId,
            'order_id' => $id,
            'paid_total' => $paidTotal,
            'paid_type' => CompanyOrderPaidRecord::PAID_TYPE_DEFAULT,
        ]);
    }

    /**
     * 删除订单支付记录
     *
     * @param int $id
     */
    public function destroyOrderPaidRecords(int $id): void
    {
        OrderPaidRecord::query()->where('order_id', $id)->delete();
    }

    /**
     * 计算订单直接支付的金额
     *
     * @param int $orderId
     * @return int
     */
    public function getDirectPaidTotal(int $orderId): int
    {
        return (int)OrderPaidRecord::query()
            ->where('order_id', $orderId)
            ->where('paid_type', OrderPaidRecord::PAID_TYPE_DEFAULT)
            ->sum('paid_total');
    }

    /**
     * @param string $refundNo
     * @return array
     */
    public function findOrderRefund(string $refundNo): array
    {
        return OrderRefund::query()
            ->where('refund_no', $refundNo)
            ->firstOrFail()
            ->toArray();
    }

    public function changeOrderRefundStatus(int $id, int $status): void
    {
        $updateData = ['status' => $status];
        if ($status === OrderRefund::STATUS_SUCCESS) {
            $updateData['success_at'] = Carbon::now()->toDateTimeLocalString();
        }
        OrderRefund::query()->where('id', $id)->update($updateData);
    }

    /**
     * @param int $limit
     * @return array
     */
    public function takeProcessingRefundOrders(int $limit): array
    {
        return OrderRefund::query()
            ->with(['order:id,order_id'])
            ->where('status', OrderRefund::STATUS_DEFAULT)
            ->orderBy('id')
            ->take($limit)
            ->get()
            ->toArray();
    }
}
